<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3.分形图案</title>
    <style>
        canvas{
            border:1px solid #aaa;
            margin: 0 auto;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="800" height="800"></canvas>

    <script src="/common/lib/gl-renderer.js"></script>

    <script type="module">
        /**
         * gl-renderer 在 WebGL 底层的基础上进行了一些简单的封装，以便于我们将重点放在提供几何数据、设置变量和编写 Shader 上，不用因为创建 buffer 等细节而分心
         * 第一步: 创建 Renderer 对象
         * 第二步: 创建并启用 WebGL 程序
         * 第三步: 设置 uniform 变量
         * 第四步: 将顶点数据送入缓冲区
         * 第五步: 渲染
        */

        //第一步:
        const canvas = document.querySelector('canvas');
        const renderer = new GlRenderer(canvas);

        
        const vertex = ` 
            attribute vec2 a_vertexPosition;
            attribute vec2 uv;
            varying vec2 vUv;
            
            void main() {
                gl_PointSize = 1.0;
                vUv = uv;
                gl_Position = vec4(a_vertexPosition, 1, 1);
            }
        `;
        /**
         * 
         */ 
        const fragment = `
            #ifdef GL_ES
            precision highp float;
            #endif
            varying vec2 vUv;
            uniform vec2 center;
            uniform float scale;
            uniform int iterations;
            
            vec3 palette(float t, vec3 c1, vec3 c2, vec3 c3, vec3 c4) {
                float x = 1.0 / 3.0;
                if (t < x) return mix(c1, c2, t/x);
                else if (t < 2.0 * x) return mix(c2, c3, (t - x)/x);
                else if (t < 3.0 * x) return mix(c3, c4, (t - 2.0*x)/x);
                return c4;
            }
            vec2 f(vec2 z, vec2 c) {
                return mat2(z, -z.y, z.x) * z + c;
            }
            void main() {
                vec2 uv = vUv;
                vec2 c = center + 4.0 * (uv - vec2(0.5)) / scale;
                vec2 z = vec2(0.0);
                bool escaped = false;
                int j;
                for (int i = 0; i < 65536; i++) {
                    if(i > iterations) break;
                    j = i;
                    z = f(z, c);
                    if (length(z) > 2.0) {
                        escaped = true;
                        break;
                    }
                }
                // gl_FragColor.rgb = escaped ? vec3(1.0) : vec3(0.0);
                gl_FragColor.rgb = escaped ? max(1.0, log(scale)) * palette(float(j)/ float(iterations), vec3(0.02, 0.02, 0.03), vec3(0.1, 0.2, 0.3), vec3(0.0, 0.3, 0.2), vec3(0.0, 0.5, 0.8))
                    : vec3(0.0);
                gl_FragColor.a = 1.0;
            }
            `;
        
        const program = renderer.compileSync(fragment, vertex);

        renderer.useProgram(program);
        // renderer.uniforms.center = [0, 0];
        // renderer.uniforms.scale = 1;
        // renderer.uniforms.iterations = 256;

        renderer.uniforms.center = [0.367, 0.303];
        renderer.uniforms.scale = 1;
        renderer.uniforms.iterations = 256;

        renderer.setMeshData([{
            positions: [
                [-1, -1],
                [-1, 1],
                [1, 1],
                [1, -1],
            ],
            attributes: {
                uv: [
                [0, 0],
                [0, 1],
                [1, 1],
                [1, 0],
                ],
            },
            cells: [[0, 1, 2], [2, 0, 3]],
        }]);

        renderer.render();


        function update() {
            const factor = Math.max(0.1, Math.log(renderer.uniforms.scale));
            renderer.uniforms.scale = (renderer.uniforms.scale += factor) % 10000;
            renderer.uniforms.iterations = factor * 500;
            requestAnimationFrame(update);
        }
        setTimeout(update, 2000);
    </script>
</body>
</html>